<!-- 自定义模板 -->
<template>
  <el-row>
    <el-col :span="4">组件</el-col>
    <el-col :span="16">画布
      <el-button @click="view()">预览</el-button>
    </el-col>
    <el-col :span="4">样式</el-col>
  </el-row>
  <el-row>
    <el-col :span="4">
      <el-card>
        <el-button @click="add('img')" type="primary">图片</el-button>
        <el-button @click="add('text')">文本</el-button>
      </el-card>
    </el-col>
    <el-col :span="16">
      <div style="display: flex;justify-content: center;" ref="model">
        <div class="card" ref="card" @contextmenu.prevent="clear">
          <div v-for="(item, index) in imgList" :key="index" @mousedown="onDragStart" :class="`img-${index}`" :ref="`img-${index}`" :style="`width:${item.width}px;height:${item.height}px;top:${item.top}px;left:${item.left}px;background-color: #bcd2f9;position: absolute;`">
            <img v-if="item.src" :src="item.src" alt="" style="width: 100%;height: 100%;" />
            <div class="indexes" v-if="indexesShow">
              {{ index + 1 }}
            </div>
          </div>
          <div v-for="(item, index) in textList" :key="index" @mousedown="onDragStart" :class="`text-${index}`" :ref="`text-${index}`" :style="`width:${item.width}px;height:${item.height}px;font-size:${item.fontSize}px;text-align:${item.textAlign};top:${item.top}px;left:${item.left}px;position: absolute;`">
            {{ item.text }}
            <div class="indexes" v-if="indexesShow">
              {{ index + 1 }}
            </div>
          </div>
        </div>
      </div>

    </el-col>
    <el-col :span="4">
      <el-card>
        <el-form ref="imgForm" label-width="80px">
          <div v-if="clickType === 'img'">
            <el-form-item label="距离顶部">
              <el-input v-model="imgList[clickIndex].top"></el-input>
            </el-form-item>
            <el-form-item label="距离左边">
              <el-input v-model="imgList[clickIndex].left"></el-input>
            </el-form-item>
            <el-form-item label="图片宽度">
              <el-input v-model="imgList[clickIndex].width"></el-input>
            </el-form-item>
            <el-form-item label="图片高度">
              <el-input v-model="imgList[clickIndex].height"></el-input>
            </el-form-item>
          </div>
          <div v-if="clickType === 'text'">
            <el-form-item label="距离顶部">
              <el-input v-model="imgList[clickIndex].top"></el-input>
            </el-form-item>
            <el-form-item label="距离左边">
              <el-input v-model="imgList[clickIndex].left"></el-input>
            </el-form-item>
            <el-form-item label="文本宽度">
              <el-input v-model="textList[clickIndex].width"></el-input>
            </el-form-item>
            <el-form-item label="文本高度">
              <el-input v-model="textList[clickIndex].height"></el-input>
            </el-form-item>
            <el-form-item label="字体大小">
              <el-input v-model="textList[clickIndex].fontSize"></el-input>
            </el-form-item>
            <el-form-item label="对齐方式">
              <el-select v-model="textList[clickIndex].textAlign">
                <el-option label="左对齐" value="left" />
                <el-option label="右对齐" value="right" />
                <el-option label="居中" value="center" />
              </el-select>
            </el-form-item>
          </div>
        </el-form>
        <div v-if="clickType != ''">
          <el-button @click="ok()">确定</el-button>
          <el-button @click="remove()">删除</el-button>
        </div>
      </el-card>
    </el-col>
  </el-row>
  <test ref="testRef" :templateHtml="templateHtml" @recover="recover" />
</template>
    
<script setup lang="ts">
import { ref, reactive, nextTick, onUnmounted } from 'vue'
import { add } from 'xe-utils'
import test from './test.vue'
// 定义元素的引用类型
const card = ref<HTMLDivElement | null>(null)
const model = ref<HTMLDivElement | null>(null)

// const pattern=reactive({
//     imgList:[],
//     textList:[]
// })
const imgList = reactive([])
const textList = reactive([])
const clickType = ref<string>('')
const clickIndex = ref<number>(-1)
const templateHtml = ref('')
const indexesShow = ref<boolean>(true)

const add = (type: string) => {
	switch (type) {
		case 'img':
			imgList.push({ top: '', left: '', width: '100', height: '100', src: '' })
			break
		case 'text':
			textList.push({ top: '', left: '', width: '100', height: '30', fontSize: '14', textAlign: 'center', text: '文本内容' })
			break
	}
}
const remove = () => {
	switch (clickType.value) {
		case 'img':
			imgList.splice(clickIndex.value, 1)
			break
		case 'text':
			textList.splice(clickIndex.value, 1)
			break
	}
	clear()
}
// 定义变量类型
let isDragging = ref<boolean>(false)
let offsetX = ref<number>(0)
let offsetY = ref<number>(0)
let dragThrottleTimer: number | null = null // 节流用的计时器

// 处理鼠标按下事件，开始拖动
const onDragStart = (e: MouseEvent): void => {
	let target = e.target as HTMLElement

	if (!target) return
	// 移除所有其他元素的 'active' 类
	document.querySelectorAll('.active').forEach(element => {
		element.classList.remove('active')
	})

	// 为当前目标元素添加 'active' 类
	if (target.classList[0] == 'indexes') {
		clear()
	} else {
		target.classList.add('active')
		clickType.value = target.classList[0].split('-')[0]
		clickIndex.value = Number(target.classList[0].split('-')[1])

		// 计算鼠标点击位置与元素的位置差 e.clientX是鼠标根据浏览器的坐标，testElement.offsetLeft是子元素相对于父元素的坐标
		offsetX.value = e.clientX - target.offsetLeft
		offsetY.value = e.clientY - target.offsetTop

		// 开始拖动
		isDragging.value = true

		// 监听鼠标移动和松开事件
		document.addEventListener('mousemove', onDragMove)
		document.addEventListener('mouseup', onDragEnd)
	}
}
// 处理鼠标移动事件，更新拖动元素的位置
const onDragMove = (e: MouseEvent): void => {
	if (!isDragging.value || !card.value || dragThrottleTimer !== null) return

	dragThrottleTimer = window.setTimeout(() => {
		const target = document.querySelector('.active') as HTMLElement
		if (!target) return

		const cardElement = card.value
		let newX = e.clientX - offsetX.value
		let newY = e.clientY - offsetY.value

		newX = Math.max(0, Math.min(newX, cardElement.offsetWidth - target.offsetWidth))
		newY = Math.max(0, Math.min(newY, cardElement.offsetHeight - target.offsetHeight))

		if (clickType.value === 'img') {
			imgList[clickIndex.value].left = newX
			imgList[clickIndex.value].top = newY
		} else if (clickType.value === 'text') {
			textList[clickIndex.value].left = newX
			textList[clickIndex.value].top = newY
		}

		dragThrottleTimer = null // 重置计时器
	}, 16) // 每帧大约 16 毫秒，约等于 60 FPS，防止快速移动鼠标时出现bug
}
// 处理鼠标松开事件，结束拖动
const onDragEnd = (): void => {
	isDragging.value = false

	// 移除鼠标事件监听
	document.removeEventListener('mousemove', onDragMove)
	document.removeEventListener('mouseup', onDragEnd)
}

const ok = () => {
	indexesShow.value = false
	const htmlContent = card.value.innerHTML
	console.log(typeof htmlContent) // 输出元素内的HTML内容
}
//清空
const clear = () => {
	// 移除所有其他元素的 'active' 类
	document.querySelectorAll('.active').forEach(element => {
		element.classList.remove('active')
	})
	clickType.value = ''
	clickIndex.value = -1
}
const testRef = ref()
const view = () => {
	indexesShow.value = false
	clear()
	nextTick(() => {
		templateHtml.value = model.value.innerHTML
		testRef.value.init(templateHtml.value)
	})
}
const recover = () => {
	indexesShow.value = true
}
</script>
    
<style lang="scss" scoped>
.card {
	position: relative;
	width: 900px;
	height: 800px;
	background-color: #fff;
	border: 1px solid #ccc;
}
.active {
	border: 2px solid #409eff !important;
}
.indexes {
	position: absolute;
	top: -20px;
	left: -20px;
	background: rgba(0, 0, 0, 0.5);
	color: white;
	padding: 2px 5px;
	border-radius: 3px;
}
</style>
    